home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 …SCII & the Runetime Code / ADC Developer CD (1992-07) (''Butch ASCII And The Runtime Code'')_iso / Dev.CD 199207.iso / Development Platforms / HyperCard Related / XCMDs & XFCNs / GetFileNames 1.1 / GetFileNames.p < prev    next >
Encoding:
Text File  |  1990-09-05  |  8.3 KB  |  320 lines  |  [TEXT/MPS ]

  1. {
  2.     Written by Chris Thorman.
  3.     Copyright 1990 Apple Computer, Inc.
  4.     
  5.     Permission granted for any kind of use as long as this notice is retained.
  6.     
  7.     Apple makes no claims as to the correctness or value of this software for
  8.     and purpose.  In fact, this software may well have bugs which will crash
  9.     your machine at crucial moments.
  10. }
  11.  
  12. {$R-}
  13. {$S GetFileNames  }
  14.  
  15.     GetFileNames [PathName], [Directories]
  16.     
  17.     This HyperCard external function returns a string containing a return-delimited
  18.     list of the file names in the directory specified by PathName.  
  19.     
  20.     If PathName is the name of a directory (ending either in the directory 
  21.     name or the directory name followed by a colon character), 
  22.     then that directory is searched.
  23.     
  24.     If PathName is the name of a file, then that file’s directory is searched (and
  25.     it will be one of the files returned if you’re asking for files).
  26.     
  27.     If PathName is not specified or is passed as empty, then the file name of the
  28.     current stack is used as a default (and files in the same directory as that 
  29.     stack are returned).
  30.     
  31.     Since elements of the return value are delimited by return characters, they
  32.     can be accessed by using the “line” operators in HyperCard.   I.e., the number
  33.     of lines in the return value is the number of files found.  Line 1 is file 1; 
  34.     line 2 is file 2, etc.
  35.  
  36.     If Directories is true, then only directory names will be returned; NOT file names.
  37.     
  38.     If the return value is empty, no files or directories were found.  [In HyperTalk, the number
  39.     of lines in empty is conveniently zero]
  40.  
  41.     If an error occurs, then the return value will be only one line long, and
  42.     will be of the form "•••••••• Error: <Descriptive Message>."    
  43.  }
  44.  
  45. UNIT DummyUnit;
  46.  
  47. INTERFACE
  48.  
  49.     USES
  50.     {    Traps, Desk, OSUtils, }
  51.         Files, ToolUtils, Memory,
  52.         Types, Events, TextEdit, Menus, HyperXCmd;
  53.  
  54.     PROCEDURE EntryPoint(paramPtr: XCmdPtr);
  55.  
  56. IMPLEMENTATION
  57.         
  58.     PROCEDURE GetFileNames (paramPtr: XCmdPtr);
  59.     FORWARD;
  60.  
  61.     PROCEDURE EntryPoint(paramPtr: XCmdPtr);
  62.     BEGIN
  63.         GetFileNames (paramPtr)
  64.     END { entrypoint } ;
  65.  
  66.         
  67.     PROCEDURE GetFileNames (paramPtr: XCmdPtr);
  68.     
  69.     CONST
  70.     
  71.     MaxParams =        2;
  72.     
  73.     TYPE
  74.     
  75.     ParamArray =        PACKED ARRAY [1..MaxParams] OF Str255;
  76.     
  77.     VAR
  78.     TheResult:            Handle;
  79.     
  80.     ParamStrings:        ParamArray;
  81.  
  82.     PathnameParam:        Str255;
  83.     DirectoriesParam:    Boolean;
  84.  
  85.     ThisDirRefNum:        Integer;
  86.     ThisVolRefNum:        Integer;
  87.     
  88.     TempString:            Str255;
  89.     TempHandle:            Handle;
  90.  
  91. PROCEDURE CleanUpBeforeFailure;
  92.         BEGIN
  93.             DisposHandle(TheResult);
  94.         END;
  95.             
  96.         PROCEDURE ExitWithHandle(aHandle: Handle);
  97.         BEGIN
  98.             ZeroTermHandle(paramPtr, aHandle);
  99.             WITH paramPtr^ DO BEGIN
  100.                 returnValue := aHandle;
  101.                 EXIT(GetFileNames);
  102.             END;
  103.         END;
  104.             
  105.         PROCEDURE ExitWithMessage(aString: Str255);
  106.         BEGIN
  107.             WITH paramPtr^ DO BEGIN
  108.                 returnValue := PasToZero(paramPtr, aString);
  109.                 EXIT(GetFileNames);
  110.             END;
  111.         END;
  112.             
  113.         PROCEDURE ExitWithError(aString: Str255);
  114.         BEGIN
  115.             ExitWithMessage(concat('•••••••• Error: ', aString, '.'));
  116.         END;
  117.             
  118.         PROCEDURE FailWithError(aString: Str255);
  119.         BEGIN
  120.             CleanUpBeforeFailure;
  121.             ExitWithError(aString);
  122.         END;
  123.             
  124.         PROCEDURE AddFileNameToResult(TheString: Str255);
  125.         VAR
  126.             OldSize: Size;
  127.             NewSize: Size;
  128.             LineFeedString: Str31;
  129.         BEGIN
  130.         
  131.             LineFeedString := ' '; LineFeedString[1] := char(13);
  132.         
  133.             OldSize := GetHandleSize(TheResult);
  134.             
  135.             IF (OldSize <> 0) THEN TheString := concat(LineFeedString, TheString); {Add a return}
  136.                 
  137.             NewSize := OldSize + length(TheString); 
  138.             SetHandleSize(TheResult, NewSize);
  139.             if (MemError <> noErr) then FailWithError('Memory Error Constructing Result.');
  140.             
  141.             BlockMove(    Ptr(ORD4(@TheString) + 1), 
  142.                         Ptr(ORD4(TheResult^) + OldSize), { OK to dereference; won’t move mem.}
  143.                         length(TheString));
  144.             
  145.         END;
  146.         
  147.         {This routine is based on Tech Note 68}
  148.         PROCEDURE EnumerShell(VolumeToSearch: LongInt; 
  149.                                 DirIDToSearch:Longint; 
  150.                                 Directories: Boolean);  
  151.         VAR
  152.         FName:               Str255;
  153.         myCPB:               CInfoPBRec;
  154.         err:                 OSErr;
  155.         TotalFiles:           integer;
  156.         TotalDirectories:    integer; 
  157.         
  158.             PROCEDURE EnumerateCatalog(dirIDToSearch: longint);
  159.             VAR
  160.             index:   integer;
  161.         
  162.             Begin {EnumerateCatalog}
  163.                 index:= 1;
  164.                 repeat
  165.                      FName:= '';
  166.                      myCPB.ioFDirIndex:= index;
  167.                      myCPB.ioDrDirID:= dirIDToSearch; {we need to do this 
  168.                                                        every time through}
  169.         
  170.                      err:= PBGetCatInfo(@myCPB,FALSE);
  171.         
  172.                      If err = noErr then 
  173.                          if BitTst(@myCPB.ioFlAttrib,3) then Begin {we have a dir}
  174.                              IF (Directories) then 
  175.                                 BEGIN
  176.                                     TotalDirectories:=TotalDirectories+1;
  177.                                     AddFileNameToResult(myCPB.ioNamePtr^);
  178.                                     { EnumerateCatalog(myCPB.ioDrDirID); } {Recursive call}
  179.                                 END;
  180.                             err:= 0;  {clear error return on way back}
  181.                             End {if BitTst}
  182.                          Else Begin {we have a file}
  183.                              IF (Not Directories) THEN
  184.                                 BEGIN
  185.                                     TotalFiles:= TotalFiles + 1;
  186.                                     AddFileNameToResult(myCPB.ioNamePtr^);
  187.                                 END;
  188.                             End; {else} 
  189.                      index:= index + 1;
  190.                  until (err <> noErr);
  191.             End;  {EnumerateCatalog}
  192.         
  193.         Begin    {EnumerShell}
  194.             TotalFiles:= 0;
  195.             TotalDirectories:= 0;
  196.         
  197.             MyCPB.ioNamePtr:= @FName; { The place where the names will be found }
  198.             MyCPB.ioVRefNum:= VolumeToSearch;    
  199.  
  200.             EnumerateCatalog(DirIDToSearch); {the root level}
  201.             
  202.         End;    {EnumerShell}
  203.         
  204.         PROCEDURE ParseParams;
  205.         VAR
  206.             ParamNum:            integer;
  207.         BEGIN
  208.             WITH paramPtr^ DO BEGIN
  209.                 IF (paramCount > MaxParams) THEN ExitWithError('Too many parameters.');
  210.                 
  211.                 IF (paramCount >= 1) THEN
  212.                     BEGIN
  213.                         ZeroToPas(paramPtr, params[1]^, ParamStrings[1]);  
  214.                         PathnameParam := ParamStrings[1];
  215.                     END
  216.                 ELSE
  217.                     BEGIN
  218.                         PathnameParam := '';
  219.                     END;    
  220.                 
  221.                 IF (PathnameParam = '') THEN
  222.                     BEGIN
  223.                         TempHandle := EvalExpr(paramPtr, 'the last word of the long name of this stack');
  224.                         ZeroToPas(ParamPtr, TempHandle^, TempString);
  225.                         DisposHandle(TempHandle);
  226.                         PathNameParam := Copy (TempString, 2, length(TempString) - 2);
  227.                     END;
  228.                 
  229.                 IF (paramCount >= 2) THEN
  230.                     BEGIN
  231.                         ZeroToPas(paramPtr, params[2]^, ParamStrings[2]);  
  232.                         DirectoriesParam := StrToBool(paramPtr, ParamStrings[2]);
  233.                     END
  234.                 ELSE
  235.                     BEGIN
  236.                         DirectoriesParam := FALSE;
  237.                     END;    
  238.                 
  239.             END;
  240.             
  241.         END;        { ParseParams }
  242.         
  243.         FUNCTION PathNameToVolRefNum(PathName: Str255; VAR VolRefNum: Integer): Boolean;
  244.         VAR
  245.             MyPB:        HParamBlockRec;
  246.             MyPBPtr:    HParmBlkPtr;
  247.             Success:    Boolean;
  248.         BEGIN
  249.         
  250.             MyPBPtr := @MyPB;
  251.             
  252.             MyPB.ioCompletion := NIL;
  253.             MyPB.ioNamePtr := @PathName;
  254.             MyPB.ioVRefNum := -1;          {* Who knows what to put here? *}
  255.             MyPB.ioVolIndex := -1;        {* Who knows what to put here? *}
  256.  
  257.             Success := (PBHGetVInfo(MyPBPtr, FALSE) = NoErr);            
  258.             
  259.             VolRefNum := MyPB.ioVRefNum;
  260.             
  261.             PathNameToVolRefNum := Success;
  262.         END;
  263.  
  264.         FUNCTION PathNameToDirRefNum(PathName: Str255; VolRefNum: Integer; VAR DirRefNum: Integer): Boolean;
  265.         VAR
  266.             MyPB:        CInfoPBRec;
  267.             MyPBPtr:    CInfoPBPtr;
  268.             Success:    Boolean;
  269.         BEGIN
  270.         
  271.             MyPBPtr := @MyPB;
  272.             
  273.             MyPB.ioCompletion := NIL;
  274.             MyPB.ioNamePtr := @PathName;
  275.             MyPB.ioVRefNum := VolRefNum;  
  276.             MyPB.ioFDirIndex := 0;        {* 0 means use ioNamePtr and ioVRefNum *}
  277.             MyPB.ioDirID := -1;            {* This is supposed to be ignored *}
  278.  
  279.             Success := (PBGetCatInfo(MyPBPtr, FALSE) = NoErr);            
  280.             
  281.             IF BitTst(@MyPB.ioFlAttrib,3) 
  282.             THEN DirRefNum := MyPB.ioDrDirID        {we have a dir -- use its dir ID}
  283.             ELSE DirRefNum := MyPB.ioFlParID;        {we have a file -- use its parent's dir ID}
  284.             
  285.             PathNameToDirRefNum := Success;
  286.         END;
  287.  
  288.     BEGIN {GetFileNames }
  289.         WITH paramPtr^ DO
  290.         BEGIN
  291.             
  292.             { Put values into PathnameParam and DirectoriesParam or fail trying }
  293.             ParseParams;    
  294.             
  295.             { Get the VolRefNum from the path name }
  296.             IF (PathNameToVolRefNum(PathnameParam, ThisVolRefNum) = FALSE)
  297.             THEN ExitWithError(concat('Couldn’t get volume from pathname: ', PathnameParam));
  298.             
  299.             { Translate the Path name and VolRefNum into a DirRefNum }
  300.             IF (PathNameToDirRefNum(PathnameParam, ThisVolRefNum, ThisDirRefNum) = FALSE)
  301.             THEN ExitWithError(concat('Couldn’t get directory from pathname: ', PathnameParam));
  302.             
  303.             { Initialize a handle for TheResult }
  304.             TheResult := NewHandle(0); { Starts off empty}
  305.             IF (TheResult = NIL) THEN ExitWithError('Memory error on NewHandle');
  306.                         
  307.             { Call the file-name-getting routine which builds onto TheResult }
  308.             EnumerShell(ThisVolRefNum, ThisDirRefNum, DirectoriesParam);
  309.             
  310.             ExitWithHandle(TheResult); { Zero-terminates it & returns it; HyperCard disposes. }
  311.             
  312.         END
  313.  
  314.     END { GetFileNames  } ;
  315.  
  316. END. { DummyUnit }
  317.  
  318.  
  319.